package com.zzc.service.impl;

import com.zzc.controller.ProductController;
import com.zzc.domain.SpikeOrder;
import com.zzc.mapper.SpikeOrderMapper;
import com.zzc.service.SpikeOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zzc.utils.RedisUtil;
import org.springframework.amqp.rabbit.annotation.Argument;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Map;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author Zzc
 * @since 2020-08-06
 */
@Service
public class SpikeOrderServiceImpl extends ServiceImpl<SpikeOrderMapper, SpikeOrder> implements SpikeOrderService {

    @Autowired
    private SpikeOrderMapper spikeOrderMapper;

    @Autowired
    private ProductServiceImpl productService;

    @Autowired
    private RedisUtil redisUtil;


    @Override
    public void createOrder(int userId, int productId) {

        SpikeOrder order = new SpikeOrder();
        order.setProductId(productId);
        order.setUserId(userId);

        spikeOrderMapper.insert(order);
    }

    /**
     * queue溢出行为，这将决定当队列达到设置的最大长度或者最大的存储空间时发送到消息队列的消息的处理方式；
     * 有效的值是：
     * drop-head（删除queue头部的消息）、
     * reject-publish（最近发来的消息将被丢弃）、
     * reject-publish-dlx（拒绝发送消息到死信交换器）
     * 类型为quorum 的queue只支持drop-head;
     */
    //从消息对列中获得秒杀请求，并进行减库存和创建订单的处理
    @Transactional(rollbackFor = Exception.class)
    @RabbitListener(queuesToDeclare = @Queue(value = "spikeOrder",
            arguments = {@Argument(name = "x-max-length", value = "10000", type = "java.lang.Integer"),  //消息队列的大小设置为10000，溢出的请求直接丢弃
            @Argument(name = "x-overflow", value = "reject-publish")}))
    public void spike(Map<String,Integer> map) {

        try {
            //数据库中的库存-1，放回修改成功的数量
            int i = productService.productInventoryDecr(map.get("productId"));
            //库存修改成功，创建订单
            if (i > 0) {
                SpikeOrder order = new SpikeOrder();
                order.setProductId( map.get("productId"));
                order.setUserId(map.get("userId"));
                spikeOrderMapper.insert(order);
            }
        } catch (Exception e) {
            e.printStackTrace();
            //如果修改库存和创建订单的过程中出现错误，修改对应的缓存
            redisUtil.incr("productInventory" + map.get("productId"), 1L);
            if (ProductController.inventoryMap.get(map.get("productId")) != null) {
                ProductController.inventoryMap.put(map.get("productId"), null);
            }
        }
    }

}
